﻿using System;
using System.Text;
using System.Configuration;
using System.Linq;
using System.IO;
using System.Diagnostics;

namespace WriteLog
{
    /// <summary>
    /// 存储日志项到文本文件
    /// 实现了ISaveLog接口
    /// </summary>
    public class SaveLogToTextFile : ConfigurationElement, ISaveLog
    {
        /// <summary>
        /// 静态的事件，用于处理当存在日志记录的时候触发
        /// 主要目的：UI的呈现
        /// </summary>
        public static event NewLogMessageInComeDelegate LogInCome;

        /// <summary>
        /// 静态的，用于记录当前的文件名称
        /// </summary>
        private static string CurrentFileName = "";

        /// <summary>
        /// 线程锁对象
        /// </summary>
        private object SyncObject = new object();

        /// <summary>
        /// 获取一个新的日志记录目录（文件夹）
        /// </summary>
        /// <returns>新的日志记录目录（文件夹）路径</returns>
        private string GetNewFolderPath()
        {
            string baseFolderPath = base["FolderPath"] as string;
            string currentFolderName = DateTime.Now.ToString("yy年MM月dd日");
            string strFormat = baseFolderPath.EndsWith(@"\", StringComparison.OrdinalIgnoreCase) ? @"{0}{1}\" : @"{0}\{1}\";
            string currentFolderPath = string.Format(strFormat, baseFolderPath, currentFolderName);
            if (!Directory.Exists(currentFolderPath))
            {
                Directory.CreateDirectory(currentFolderPath);
            }
            return currentFolderPath;
        }
        /// <summary>
        /// 存储日志文件的总路径
        /// 会自动根据日期分目录
        /// </summary>
        [ConfigurationProperty("FolderPath", IsRequired = true)]
        private string FolderPath
        {
            get
            {
                return GetNewFolderPath();
            }
        }
        /// <summary>
        /// 日志文件的扩展名
        /// </summary>
        [ConfigurationProperty("ExtensionName", IsRequired = true)]
        private string ExtensionName
        {
            get
            {
                return base["ExtensionName"] as string;
            }
        }

        /// <summary>
        /// 日志文件记录规则
        /// 如：文件名、大小、分割规则
        /// </summary>
        [ConfigurationProperty("LogFileRule", IsRequired = true)]
        private TxtLogFileRule LogFileRule
        {
            get
            {
                return base["LogFileRule"] as TxtLogFileRule;
            }
        }

        private string TextFileName
        {
            get
            {
                string strFormat;
                strFormat = this.FolderPath.EndsWith(@"\", StringComparison.OrdinalIgnoreCase) ? @"{0}{1}.{2}" : @"{0}\{1}.{2}";
                return string.Format(
                    strFormat,
                    this.FolderPath,
                    GetFileName(),
                    this.ExtensionName);
            }
        }


        /// <summary>
        /// 获取一个可以存储日志内容的文本文件名称
        /// </summary>
        /// <returns></returns>
        private string GetFileName()
        {
            lock (CurrentFileName)
            {
                if (string.IsNullOrEmpty(CurrentFileName))
                    CurrentFileName = GetLastLogFileName(FolderPath);
            }

            string fullName = string.Format("{0}{1}.{2}",FolderPath,CurrentFileName,ExtensionName);

            if(!File.Exists(fullName))
            {
                FileStream fs = File.Create(fullName);
                fs.Close();
                fs.Dispose();
            }

            FileInfo _currentFileInfo = new FileInfo(fullName);
            switch (LogFileRule.PartRule)
            {
                case FilePartRule.AssignSize:
                    if (_currentFileInfo.Length >= LogFileRule.FileSize * 1024)
                    {
                        return GetNewFileNameString();
                    }
                    return CurrentFileName;
                case FilePartRule.PerItem:
                    if ((_currentFileInfo.CreationTime - DateTime.Now).Days >= 1)
                    {
                        return GetNewFileNameString();
                    }
                    return CurrentFileName;
                case FilePartRule.HourItem:
                    if ((_currentFileInfo.CreationTime - DateTime.Now).Hours >= 1)
                    {
                        return GetNewFileNameString();
                    }
                    return CurrentFileName;
                default:
                    return CurrentFileName;
            }
        }

        private string GetLastLogFileName(string path)
        {
            DirectoryInfo di = new DirectoryInfo(path);
            FileInfo[] files = di.GetFiles(string.Format("*.{0}", ExtensionName));
            if (files.Length == 0)
                return GetNewFileNameString();
            else
            {
                string lastfilename = files.OrderBy(file => file.CreationTime).Last().Name;
                return lastfilename.Substring(0, lastfilename.IndexOf("."));
            }
        }

        private string GetNewFileNameString()
        {
            lock (CurrentFileName)
            {
                switch (LogFileRule.NameRule)
                {
                    case FileNameRule.Time:
                        CurrentFileName = DateTime.Now.ToString("yyyyMMddhhmmss");
                        break;
                    case FileNameRule.Guid:
                        CurrentFileName = Guid.NewGuid().ToString("N");
                        break;
                    default:
                        CurrentFileName = DateTime.Now.ToString("yyyyMMddhhmmss");
                        break;
                }
            }
            return CurrentFileName;
        }

        #region ISaveLog接口内容
        public void Save(BaseLogMessage log)
        {
            lock (SyncObject)
            {
                try
                {
                    CancelEventArgs cea = new CancelEventArgs();
                    if (LogInCome != null)
                    {
                        cea.LogMsg = log;
                        cea.CancelSave = false;
                        LogInCome.Invoke(cea);          //似乎只有同步执行了
                    }

                    if (cea.CancelSave) return;

                    using (FileStream fs = new FileStream(this.TextFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
                    {
                        byte[] writeBody = Encoding.Default.GetBytes(log.ToString());
                        fs.Position = fs.Length;
                        byte[] newLine = Encoding.Default.GetBytes(System.Environment.NewLine);
                        fs.Write(newLine, 0, newLine.Length);
                        fs.Write(writeBody, 0, writeBody.Length);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("写入日志文件时出现错误：{0}{1}将不做任何处理。", e.Message,System.Environment.NewLine);
                }
            }
        }

        public void Save(string logMessage)
        {
            NormalLogMessage log = new NormalLogMessage(logMessage);
            this.Save(log);
        }
        #endregion
    }
}
